using System.Collections.Generic;
using System.Web.Routing;
using Nop.Core.Domain.Cms;
using Nop.Core.Plugins;
using Nop.Services.Cms;
using Nop.Services.Configuration;
using Nop.Services.Localization;
using Nop.Core.Events;
using Nop.Core.Domain.Orders;
using Nop.Services.Messages;
using System.Net;
using System.IO;
using Nop.Services.Common;
using Nop.Services.Logging;
using System;
using Nop.Core.Caching;
using Nop.Core.Infrastructure;
using Nop.Services.Orders;
using Nop.Core;
using Nop.Services.Customers;
using Nop.Core.Domain.Customers;

namespace Nop.Plugin.Widgets.ShoppingMail
{
    /// <summary>
    /// Live person provider
    /// </summary>
    public class ShoppingMailPlugin : BasePlugin, IWidgetPlugin, IMiscPlugin, IConsumer<MessageTokensAdded<Token>>
    {
        private readonly IWorkContext _workContext;
        private readonly ISettingService _settingService;
        private readonly IOrderService _orderService;
        private readonly ICacheManager _cacheManager;
        private readonly ShoppingMailSettings _ShoppingMailSettings;

        private readonly ILogger _logger;

        public ShoppingMailPlugin(IWorkContext workContext,
            ISettingService settingService,
            IOrderService orderService,
            ICacheManager cacheManager,
            ShoppingMailSettings ShoppingMailSettings,
            ILogger logger)
        {
            this._workContext = workContext;
            this._settingService = settingService;
            this._orderService = orderService;
            this._cacheManager = cacheManager;
            this._ShoppingMailSettings = ShoppingMailSettings;
            this._logger = logger;
        }



        #region IConsumer<TokensAdded<Order,IList<Token>>> Membres

        public void HandleEvent(MessageTokensAdded<Token> eventMessage)
        {
            if (_ShoppingMailSettings.IncludeBannerInMails
                && (eventMessage.Message.Name == "OrderPlaced.CustomerNotification" || eventMessage.Message.Name == "ShipmentSent.CustomerNotification"))
            {

                string key = Nop.Plugin.Widgets.ShoppingMail.Controllers.WidgetsShoppingMailController.HTMLADD_KEY;

                var HtmlAd = _cacheManager.Get(key, 3600, () =>
                {
                    string fullResponse = "";
                    try
                    {
                        var lastOrder = GetLastOrder();

                        //call service with eventMessage.Entity.ShippingMethod
                        string serviceUrl;
                        if (_ShoppingMailSettings.UseSandbox)
                            serviceUrl = "http://www.shopping-mail.com/service/work_demo.php?";
                        else     
                            serviceUrl = "http://www.shopping-mail.com/service/work.php?";

                        string parametersUrl;
                        if (_ShoppingMailSettings.UseSandbox)
                            parametersUrl = string.Format("token={0}&order_id={1}", "3aom9n45px4wggosow8sookooc4cwg0s44wos4gwc4ssgo4oso", lastOrder.Id);
                        else
                            parametersUrl = string.Format("token={0}&order_id={1}", _ShoppingMailSettings.Token, lastOrder.Id);

                        if (eventMessage.Message.Name == "OrderPlaced.CustomerNotification")
                            parametersUrl += string.Format("&mail_type={0}", "order");
                        if (eventMessage.Message.Name == "ShipmentSent.CustomerNotification")
                            parametersUrl += string.Format("&mail_type={0}", "shipping");

                        //parametersUrl += string.Format("&code={0}", DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss"));
                        parametersUrl += string.Format("&code={0}", DateTime.Now.ToUnixTimestamp());

                        if (_ShoppingMailSettings.UseDynamicTargeting)
                        {
                            parametersUrl += string.Format("&country={0}", lastOrder.ShippingAddress.Country.TwoLetterIsoCode);
                            
                            var dateOfBirth = _workContext.CurrentCustomer.GetAttribute<DateTime?>(SystemCustomerAttributeNames.DateOfBirth);
                            if (dateOfBirth.HasValue)
                                parametersUrl += string.Format("&birthday={0}", dateOfBirth.Value.ToString("dd/MM/yyyy"));

                            if (false)
                                parametersUrl += string.Format("&genders={0}", "");
                        }
                        string completeUrl = serviceUrl + parametersUrl;
                        var request = WebRequest.Create(completeUrl) as HttpWebRequest;
                        request.Timeout = 2000;
                        request.ReadWriteTimeout = request.Timeout;
                        using (WebResponse response = request.GetResponse())
                        {
                            using (Stream responseStream = response.GetResponseStream())
                            {
                                using (StreamReader streamResponse = new StreamReader(responseStream))
                                {
                                    fullResponse = streamResponse.ReadToEnd().Trim();
                                }
                            }
                        }
                        return fullResponse;
                    }
                    catch (Exception ex)
                    {
                        _logger.InsertLog(Core.Domain.Logging.LogLevel.Error, "Error creating token for ShoppingMail", ex.ToString());
                        return ""; ;
                    }

                });

                eventMessage.Tokens.Add(new Token("ShoppingMail.Banner", HtmlAd, true));
            }

        }

        Order lastOrder = null;
        private Order GetLastOrder()
        {
            if (lastOrder == null)
            {
                var orders = _orderService.GetOrdersByCustomerId(_workContext.CurrentCustomer.Id);
                if (orders.Count != 0)
                {
                    lastOrder = orders[0];
                }
            }
            return lastOrder;
        }
        #endregion



        /// <summary>
        /// Get a list of supported widget zones; if empty list is returned, then all zones are supported
        /// </summary>
        /// <returns>A list of supported widget zones</returns>
        public IList<WidgetZone> SupportedWidgetZones()
        {
            //limit widget to the following zones
            return new List<WidgetZone>() 
            { 
                WidgetZone.HeadHtmlTag, 
                WidgetZone.BeforeBodyEndHtmlTag
            };
        }


        public void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues)
        {
            actionName = "Configure";
            controllerName = "WidgetsShoppingMail";
            routeValues = new RouteValueDictionary() { { "Namespaces", "Nop.Plugin.Misc.ShoppingMail.Controllers" }, { "area", null } };
        }

        /// <summary>
        /// Gets a route for provider configuration
        /// </summary>
        /// <param name="widgetId">Widget identifier</param>
        /// <param name="actionName">Action name</param>
        /// <param name="controllerName">Controller name</param>
        /// <param name="routeValues">Route values</param>
        public void GetConfigurationRoute(int widgetId, out string actionName, out string controllerName, out RouteValueDictionary routeValues)
        {
            actionName = "ConfigureWidget";
            controllerName = "WidgetsShoppingMail";
            routeValues = new RouteValueDictionary() { { "Namespaces", "Nop.Plugin.Widgets.ShoppingMail.Controllers" }, { "area", null }, { "widgetId", widgetId } };
        }

        /// <summary>
        /// Gets a route for displaying widget
        /// </summary>
        /// <param name="widgetId">Widget identifier</param>
        /// <param name="actionName">Action name</param>
        /// <param name="controllerName">Controller name</param>
        /// <param name="routeValues">Route values</param>
        public void GetDisplayWidgetRoute(int widgetId, out string actionName, out string controllerName, out RouteValueDictionary routeValues)
        {
            actionName = "PublicInfo";
            controllerName = "WidgetsShoppingMail";
            routeValues = new RouteValueDictionary() { { "Namespaces", "Nop.Plugin.Widgets.ShoppingMail.Controllers" }, { "area", null }, { "widgetId", widgetId } };
        }

        /// <summary>
        /// Install plugin
        /// </summary>
        public override void Install()
        {
            var settings = new ShoppingMailSettings()
            {
                IncludeBannerInMails = false,
                Token = @"3aom9n45px4wggosow8sookooc4cwg0s44wos4gwc4ssgo4oso",
                UseDynamicTargeting = false,
                UseSandbox = true,
            };
            _settingService.SaveSetting(settings);

            this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.ShoppingMail.IncludeBannerInMails", "Include banner in mails");
            this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.ShoppingMail.IncludeBannerInMails.Hint", "Check to allow plugin to include banner in 'order placed' and 'shippment send' emails. This implies that you include in your template %ShoppingMail.Banner% token");
            this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.ShoppingMail.Token", "ShoppingMail Token");
            this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.ShoppingMail.Token.Hint", "ShoppingMail Token");
            this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.ShoppingMail.UseDynamicTargeting", "Use dynamic targeting");
            this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.ShoppingMail.UseDynamicTargeting.Hint", "Check to allow the plugin to use country, gender and birthday to target customers.");
            this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.ShoppingMail.UseSandbox", "Use test url");
            this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.ShoppingMail.UseSandbox.Hint", "Check to use test url");
            this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.ShoppingMail.TrackingScript", "ShoppingMail traking script");
            this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.ShoppingMail.TrackingScript.Hint", "Paste ShoppingMail tracking code. {TOKEN}, {Order_Amount}, {Order_id} will be dynamically replaced. http will also be automatically replaced with https when necessary.");

            base.Install();
        }

        /// <summary>
        /// Uninstall plugin
        /// </summary>
        public override void Uninstall()
        {
            //locales
            this.DeletePluginLocaleResource("Plugins.Widgets.ShoppingMail.IncludeBannerInMails");
            this.DeletePluginLocaleResource("Plugins.Widgets.ShoppingMail.IncludeBannerInMails.Hint");
            this.DeletePluginLocaleResource("Plugins.Widgets.ShoppingMail.Token");
            this.DeletePluginLocaleResource("Plugins.Widgets.ShoppingMail.Token.Hint");
            this.DeletePluginLocaleResource("Plugins.Widgets.ShoppingMail.UseDynamicTargeting");
            this.DeletePluginLocaleResource("Plugins.Widgets.ShoppingMail.UseDynamicTargeting.Hint");
            this.DeletePluginLocaleResource("Plugins.Widgets.ShoppingMail.UseSandbox");
            this.DeletePluginLocaleResource("Plugins.Widgets.ShoppingMail.UseSandbox.Hint");
            this.DeletePluginLocaleResource("Plugins.Widgets.ShoppingMail.TrackingScript");
            this.DeletePluginLocaleResource("Plugins.Widgets.ShoppingMail.TrackingScript.Hint");

            base.Uninstall();
        }
    }

    public static class DateTimeStuff
    {
        private static DateTime unixRef = new DateTime(1970, 1, 1, 0, 0, 0);
        public static long ToUnixTimestamp(this DateTime dt)
        {
            return (dt.Ticks - unixRef.Ticks) / 10000000;
        }
        public static DateTime FromUnixTimestamp(long timestamp)
        {
            return unixRef.AddSeconds(timestamp);
        }

    }
}
